home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 July: Mac OS SDK / Dev.CD Jul 97 SDK1.toast / Development Kits (Disc 1) / QuickDraw 3D / Samples / SampleCode / Tumbler and Podium / Tumbler_camera.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-21  |  11.4 KB  |  423 lines  |  [TEXT/MPS ]

  1. #include <FixMath.h>
  2.  
  3. #include "Tumbler_globals.h"
  4.  
  5. #include "QD3D.h"
  6. #include "QD3DDrawContext.h"
  7. #include "QD3DDrawContext.h"
  8. #include "QD3DCamera.h"
  9. #include "QD3DView.h"
  10. #include "QD3DRenderer.h"
  11. #include "QD3DGroup.h"
  12. #include "QD3DMath.h"
  13.  
  14. #include "Tumbler_prototypes.h"
  15.  
  16. #include "QD3DGeometry.h"
  17. #include "QD3DLight.h"
  18.  
  19. #include "Tumbler_camera.h"
  20.  
  21. void GetGroupBBox(
  22.     TQ3ViewObject        viewObject,
  23.     TQ3GroupObject        mainGroup,
  24.     TQ3GroupObject        lightGroup,
  25.     TQ3BoundingBox         *viewBBox)
  26. {
  27.     TQ3Point3D                     from     = { 0.0, 0.0, 1.0 };
  28.     TQ3Point3D                     to         = { 0.0, 0.0, 0.0 };
  29.     TQ3Vector3D                     up         = { 0.0, 1.0, 0.0 };
  30.     
  31.     float                         fieldOfView = .52359333333;
  32.     float                         hither         =  0.5;
  33.     float                         yon         =  1.5;
  34.  
  35.     TQ3Status                    status;
  36.     
  37.     Q3View_StartBoundingBox(viewObject, kQ3ComputeBoundsExact);
  38.     do {
  39.         status = Q3DisplayGroup_Submit(mainGroup, viewObject);
  40.     } while (Q3View_EndBoundingBox(viewObject, viewBBox) == kQ3ViewStatusRetraverse);
  41.                                         
  42.     //
  43.     //  If we have a point model, then the "viewBBox" would end up
  44.     //  being a "singularity" at the location of the point.  As
  45.     //  this bounding "box" is used in setting up the camera spec,
  46.     //  we get bogus input into Escher.
  47.     
  48.     {
  49.          float        xSize, ySize, zSize;
  50.         
  51.         xSize = viewBBox->max.x - viewBBox->min.x;
  52.         ySize = viewBBox->max.y - viewBBox->min.y;
  53.         zSize = viewBBox->max.z - viewBBox->min.z;
  54.  
  55.         if (xSize <= kQ3RealZero &&
  56.             ySize <= kQ3RealZero &&
  57.             zSize <= kQ3RealZero) {
  58.             
  59.             viewBBox->max.x += 0.0001;
  60.             viewBBox->max.y += 0.0001;
  61.             viewBBox->max.z += 0.0001;
  62.             
  63.             viewBBox->min.x -= 0.0001;
  64.             viewBBox->min.y -= 0.0001;
  65.             viewBBox->min.z -= 0.0001;
  66.         }
  67.     }
  68. }
  69.  
  70. #define    SIZESCALE    0.03
  71. #define POSSCALE    0.5
  72. void AdjustLightsPositions(
  73.     DocumentPtr theDocument)
  74. {
  75. #if defined(ESCHER_VER_15) && ESCHER_VER_15
  76.  
  77.     TQ3BoundingBox         viewBBox;
  78.      TQ3Vector3D            diagonalVector, radius;
  79.     TQ3GroupPosition        position, lightPosition;
  80.     TQ3Object            ellipsoid;
  81.     TQ3Point3D            origin;
  82.     float                maxDimension;
  83.     TQ3GroupObject        lightGroup;
  84.     TQ3LightObject        theLight;
  85.     float        ratio;
  86.     
  87.     GetGroupBBox(theDocument->theView, theDocument->documentGroup, nil, &viewBBox);
  88.  
  89.     Q3Point3D_Subtract(&viewBBox.max,
  90.                        &viewBBox.min,
  91.                        &diagonalVector);
  92.     maxDimension = Q3Vector3D_Length(&diagonalVector);
  93.     maxDimension *= 8.0 / 7.0;
  94.     
  95.     ratio = 6.0 / maxDimension;
  96.     
  97.     /* Adjust the light from the viewer first */
  98.     
  99.     Q3View_GetLightGroup(theDocument->theView, &lightGroup);
  100.         
  101.     Q3Group_GetFirstPosition(lightGroup, &lightPosition);
  102.  
  103.     Q3Group_GetPositionObject(lightGroup, lightPosition, &theLight);
  104.     
  105.     origin.x = -10.0;
  106.     origin.y = 10.0;
  107.     origin.z = 30.0;
  108.     
  109.     Q3PointLight_SetLocation(theLight, &origin);
  110.     Q3Object_Dispose(theLight);
  111.     
  112.     /* Set the geometry and the light parameters for the red light */
  113.     Q3Group_GetFirstPositionOfType(theDocument->light1,
  114.         kQ3ShapeTypeGeometry, &position);
  115.  
  116.     Q3Group_GetPositionObject(theDocument->light1, position, &ellipsoid);
  117.     
  118.     origin.x = ratio * diagonalVector.x * POSSCALE;
  119.     origin.y = ratio *  diagonalVector.y * POSSCALE;
  120.     origin.z =  ratio * diagonalVector.z * POSSCALE;
  121.     Q3Ellipsoid_SetOrigin( ellipsoid, &origin);
  122.     
  123.     radius.x = radius.z = 0.0;
  124.     radius.y = ratio * maxDimension * SIZESCALE;
  125.     Q3Ellipsoid_SetOrientation( ellipsoid, &radius);
  126.     
  127.     radius.x = radius.y = 0.0;
  128.     radius.z = ratio * maxDimension * SIZESCALE;
  129.     Q3Ellipsoid_SetMajorRadius( ellipsoid, &radius);
  130.     
  131.     radius.z = radius.y = 0.0;
  132.     radius.x = ratio * maxDimension * SIZESCALE;
  133.     Q3Ellipsoid_SetMinorRadius( ellipsoid, &radius);
  134.  
  135.     Q3Group_GetNextPosition(lightGroup, &lightPosition);
  136.     Q3Group_GetPositionObject(lightGroup, lightPosition, &theLight);    
  137.     Q3PointLight_SetLocation(theLight, &origin);
  138.     
  139.     Q3Object_Dispose(theLight);
  140.     
  141.     Q3Object_Dispose(ellipsoid);
  142.     
  143.     
  144.     /* Set the geometry and the light parameters for the green light */
  145.     Q3Group_GetFirstPositionOfType(theDocument->light2,
  146.         kQ3ShapeTypeGeometry, &position);
  147.  
  148.     Q3Group_GetPositionObject(theDocument->light2, position, &ellipsoid);
  149.     
  150.     origin.x = - ratio * diagonalVector.x * POSSCALE;
  151.     origin.y = - ratio *  diagonalVector.y *  POSSCALE;
  152.     origin.z = ratio * diagonalVector.z * POSSCALE;
  153.     Q3Ellipsoid_SetOrigin( ellipsoid, &origin);
  154.     
  155.     radius.x = radius.z = 0.0;
  156.     radius.y = ratio * maxDimension * SIZESCALE;
  157.     Q3Ellipsoid_SetOrientation( ellipsoid, &radius);
  158.     
  159.     radius.x = radius.y = 0.0;
  160.     radius.z = ratio * maxDimension * SIZESCALE;
  161.     Q3Ellipsoid_SetMajorRadius( ellipsoid, &radius);
  162.     
  163.     radius.z = radius.y = 0.0;
  164.     radius.x = ratio * maxDimension * SIZESCALE;
  165.     Q3Ellipsoid_SetMinorRadius( ellipsoid, &radius);
  166.     
  167.     Q3Group_GetNextPosition(lightGroup, &lightPosition);
  168.     Q3Group_GetPositionObject(lightGroup, lightPosition, &theLight);    
  169.     Q3PointLight_SetLocation(theLight, &origin);
  170.     
  171.     Q3Object_Dispose(theLight);
  172.     Q3Object_Dispose(ellipsoid);
  173.     
  174.     /* Set the geometry and the light parameters for the blue light */
  175.     Q3Group_GetFirstPositionOfType(theDocument->light3,
  176.         kQ3ShapeTypeGeometry, &position);
  177.  
  178.     Q3Group_GetPositionObject(theDocument->light3, position, &ellipsoid);
  179.     
  180.     origin.x = 0.0;
  181.     origin.y =  ratio * diagonalVector.y * POSSCALE + 1.0;
  182.     origin.z =  0.0;
  183.     Q3Ellipsoid_SetOrigin( ellipsoid, &origin);
  184.     
  185.     radius.x = radius.z = 0.0;
  186.     radius.y = ratio * maxDimension * SIZESCALE;
  187.     Q3Ellipsoid_SetOrientation( ellipsoid, &radius);
  188.     
  189.     radius.x = radius.y = 0.0;
  190.     radius.z = ratio * maxDimension * SIZESCALE;
  191.     Q3Ellipsoid_SetMajorRadius( ellipsoid, &radius);
  192.     
  193.     radius.z = radius.y = 0.0;
  194.     radius.x = ratio * maxDimension * SIZESCALE;
  195.     Q3Ellipsoid_SetMinorRadius( ellipsoid, &radius);
  196.  
  197.     Q3Group_GetNextPosition(lightGroup, &lightPosition);
  198.     Q3Group_GetPositionObject(lightGroup, lightPosition, &theLight);    
  199.     Q3PointLight_SetLocation(theLight, &origin);
  200.     
  201.     Q3Object_Dispose(theLight);
  202.     Q3Object_Dispose(ellipsoid);
  203.  
  204.     Q3Object_Dispose(lightGroup);
  205. #endif
  206. }
  207.  
  208.  
  209.  
  210. //===========================================================================
  211. //
  212. //    Routine:    AdjustCamera()
  213. //
  214. //    Comments:    
  215. //
  216. //===========================================================================
  217.  
  218. TQ3Point3D AdjustCamera(
  219.     DocumentPtr theDocument,
  220.     short                winWidth,
  221.     short                winHeight)
  222. {
  223.     float                         fieldOfView;
  224.     float                         hither;
  225.     float                         yon;
  226.     TQ3CameraPlacement            placement;
  227.     TQ3CameraRange                range;
  228.     TQ3BoundingBox                 viewBBox;
  229.     long                         fromAxis;    
  230.     float                         maxDimension;
  231.      float                        xSize, ySize, zSize;
  232.     float                        weights[2] = { 0.5, 0.5 };
  233.     TQ3Point3D                    points[2];
  234.     TQ3Vector3D                     viewVector;
  235.     TQ3Vector3D                    normViewVector;
  236.     TQ3Vector3D                    eyeToFrontClip;
  237.     TQ3Vector3D                    eyeToBackClip;
  238.     float                        viewDistance;
  239.     TQ3Vector3D                    diagonalVector;
  240.     float                        ratio;
  241.     TQ3CameraObject                camera;
  242.     
  243.     Q3View_GetCamera(theDocument->theView, &camera);
  244.     
  245.     GetGroupBBox(theDocument->theView, theDocument->documentGroup, 
  246.         theDocument->dynamicLights, &viewBBox);
  247.  
  248.     /*
  249.      *  If we have a point model, then the "viewBBox" would end up
  250.      *  being a "singularity" at the location of the point.  As
  251.      *  this bounding "box" is used in setting up the camera spec,
  252.      *  we get bogus input into Escher.
  253.      *
  254.      *    Therefore, determine if the bounding box is really really small
  255.      *    (kQ3RealZero) and increase it so it's just a little small.
  256.      */
  257.     xSize = viewBBox.max.x - viewBBox.min.x;
  258.     ySize = viewBBox.max.y - viewBBox.min.y;
  259.     zSize = viewBBox.max.z - viewBBox.min.z;
  260.  
  261.     if (xSize <= kQ3RealZero &&
  262.         ySize <= kQ3RealZero &&
  263.         zSize <= kQ3RealZero)  
  264.     {
  265.         viewBBox.max.x += 0.0001;
  266.         viewBBox.max.y += 0.0001;
  267.         viewBBox.max.z += 0.0001;
  268.         
  269.         viewBBox.min.x -= 0.0001;
  270.         viewBBox.min.y -= 0.0001;
  271.         viewBBox.min.z -= 0.0001;
  272.     }
  273.  
  274.     points[0] = viewBBox.min;
  275.     points[1] = viewBBox.max;
  276.  
  277.     /* 
  278.         This sets the "documentGroupCenter" to the center of our bbox.
  279.         
  280.         (point[0] * weight[0] + point[1] * weight[1]) or
  281.         
  282.         (point[0] * 0.5 + point[1] * 0.5) or
  283.         
  284.         point[0] + point[1]
  285.         -------------------, essentially, the average of the points.
  286.                  2
  287.     */
  288.     Q3Point3D_AffineComb(points, weights, 2, &theDocument->documentGroupCenter);
  289.  
  290.     /*
  291.      *  The "from" point is on a vector perpendicular to the plane
  292.      *  in which the bounding box has greatest dimension.  As "up" is
  293.      *  always in the positive y direction, look at x and z directions.
  294.      */
  295.     xSize = viewBBox.max.x - viewBBox.min.x;
  296.     zSize = viewBBox.max.z - viewBBox.min.z;
  297.     
  298.     if (xSize > zSize) {
  299.         fromAxis = kQ3AxisZ;
  300.     } else {
  301.         fromAxis = kQ3AxisX;
  302.     }
  303.  
  304.     /*
  305.      *  Compute the length of the diagonal of the bounding box.
  306.      *
  307.      *  The hither and yon planes are adjusted so that the
  308.       *  diagonal of the bounding box is 7/8 the size of the
  309.       *  minimum dimension of the view frustum. The diagonal is used instead
  310.       *  of the maximum size (in x, y, or z) so that when you rotate
  311.       *  the object, the corners don't get clipped out.
  312.       */
  313.     Q3Point3D_Subtract(
  314.         &viewBBox.max,
  315.         &viewBBox.min,
  316.         &diagonalVector);
  317.  
  318.     maxDimension    =    Q3Vector3D_Length(&diagonalVector);
  319.     maxDimension    *=    8.0 / 7.0;
  320.     
  321.     /* 
  322.         This scales all objects in the scene so they gets scaled to fit
  323.         in the window. We're using the length of the diagonal of the box
  324.         to scale. We can now assume the maximum dimension of the model is
  325.         1.0.
  326.     */
  327.     ratio = 1.0 / maxDimension;
  328.             
  329.     theDocument->documentGroupScale = ratio;
  330.     
  331.     /*
  332.         Now, adjust the camera's hither and yon planes.
  333.         
  334.         (We don't edit the camera location, etc. as it will always be in
  335.         the same location - we always scale the objects and leave the camera
  336.         in the same location.)
  337.     */
  338.     Q3Camera_GetPlacement(camera, &placement);
  339.  
  340.     /*
  341.          Compute the camera vector
  342.     */
  343.     Q3Point3D_Subtract(
  344.         &placement.cameraLocation,
  345.         &placement.pointOfInterest,
  346.         &viewVector);
  347.  
  348.     viewDistance = Q3Vector3D_Length(&viewVector);
  349.     Q3Vector3D_Normalize(&viewVector, &normViewVector);
  350.  
  351.     /*    
  352.         Essentially, here we are "scaling" the normalized camera vector
  353.         to a location in front of the object (half of maxDimension)
  354.         and another location in back of the camera.
  355.         
  356.         Assume these three vectors below are co-linear.
  357.                                     
  358.         A = ratio * maxDimension/2.0
  359.         
  360.         |------hither-------||----A----|----A-----|
  361.         |------------------yon--------------------|
  362.         
  363.         camera location                        
  364.         * -----------------> * eyeToFrontClip
  365.         * --------camera vector------> * object center
  366.         * --------------------------------------> * eyeToBackClip
  367.     */
  368.     
  369.     Q3Vector3D_Scale(&normViewVector, 
  370.                      viewDistance - ratio * maxDimension/2.0,
  371.                      &eyeToFrontClip);
  372.                     
  373.     Q3Vector3D_Scale(&normViewVector, 
  374.                     viewDistance + ratio * maxDimension/2.0,
  375.                     &eyeToBackClip);
  376.  
  377.     hither     = Q3Vector3D_Length(&eyeToFrontClip);
  378.     yon     = Q3Vector3D_Length(&eyeToBackClip);
  379.     
  380.     /*
  381.         Set the field of view. This will determine the width of our lens.
  382.         Or, (more appropriately), as someone here mentioned,
  383.         where the blinders begin in our image.
  384.         
  385.         This is the angle created by the triangle of the camera vector and the
  386.         maximum dimension of our object.
  387.         
  388.         We use the hither point because it's closest and convenient.
  389.         
  390.         we know:
  391.         
  392.         atan(opposite/adjacent) = the angle we need
  393.         
  394.         Our angle is at the camera, so our "opposite" leg is "A" (above)
  395.         our "adjacent" leg is the hither length.
  396.         
  397.         We double our result because our triangle gets us the half angle
  398.         for the entire field of view. 
  399.     */
  400.     
  401.     fieldOfView = 2 * atan((ratio * maxDimension/2.0)/hither);
  402.  
  403.     range.hither                 = hither;
  404.     range.yon                     = yon;
  405.  
  406.     Q3Camera_SetRange(camera, &range);
  407.  
  408.     Q3ViewAngleAspectCamera_SetFOV(
  409.         camera, fieldOfView);
  410.  
  411.     /* 
  412.         And finally, set up our aspect ratio depending on how big the 
  413.         window is.
  414.     */
  415.     Q3ViewAngleAspectCamera_SetAspectRatio(
  416.         camera, (float) winWidth / (float) winHeight);
  417.  
  418.     Q3Object_Dispose(camera);
  419.     
  420.     return(theDocument->documentGroupCenter);
  421. }
  422.  
  423.